﻿#include "alarm.h"
#include <algorithm>


DWORD CAlarm::WorkThread(void *arg)
{
    CAlarm *pThis = (CAlarm *)arg;

    pThis->Run();

    return NULL;

}

void CAlarm::Run()
{   
    time_t lastTime = 0;
    bool status = false;

    while (1)
    {
        if (this->m_pSocket==NULL || this->m_pSocket->GetValidLineCount() == 0)
        {
            this->ClearAllChannelStatus();
            this->ClearAllBackupAlarm();
            m_LastAlarmRects.clear();
            Sleep(1);
            continue;
        }

        m_locker.lock();

        //如果有备份数据，则每2秒向后端发送一个数据（此数据为随机从备份列表中取得）
        if (this->m_backupAlarms.size() > 0 && this->m_pSocket->GetValidLineCount() > 0)
        {
            if (!this->m_backupAlarms.empty())
            {
            
                BackupAlarms::iterator backupBuffer = this->m_backupAlarms.begin();
                AlarmNet backAlarm = *backupBuffer;
                
                this->m_backupAlarms.erase(backupBuffer);
                if (!status)
                {
                    lastTime = backAlarm.alarmInfo.time;
                }

                if ((time(0) - lastTime) > 15 && !backAlarm.ackknowleged)
                {
                    CJSByteArray byteArr(128 * 1024);
                    
                    CDIB *dibImage = cvCvtIMG2DIB(backAlarm.pIplImage);
                    int nPackLen = PackAlarm(byteArr, backAlarm.alarmInfo, backAlarm.rects, *dibImage);
                    delete dibImage;

                    if (nPackLen > 0)
                    {
                        if (this->m_pSocket->GetValidLineCount() > 0)
                        {
                            int len = this->m_pSocket->SendData(
                                this->m_pSocket->GetLineByIndex(0),
                                byteArr.GetData(), byteArr.Length());
                            printf("Send Backup Alarm, length=%d\n", len);
                        }
                    }

                    lastTime = time(0);  //时间更新，等待下一个2秒，再发数据
                    status = true;       //status标志，只为备份数据从无到有的时候第一次取数据所有到
                    //printf(">2add to back\n");

                }
                
                m_backupAlarms.push_back(backAlarm);
               
            }
            
        }
        else
        {
            status = false;
        }
        Sleep(1);

        m_locker.unlock();
    }
}

CAlarm::CAlarm()
{
    ClearAllChannelStatus();
    m_LastAlarmRects.clear();

    m_nWarnID = 0;
    m_AckInfo = 0x00;

    m_pSocket = NULL;

    CreateThread(NULL, 0, WorkThread, this, 0, &m_backupAlarmSendTh);
    //CreateThread(NULL, 0, WorkThread, )
    
}

CAlarm::~CAlarm()
{
    ClearAllChannelStatus();
    m_LastAlarmRects.clear();
    m_AckInfo = 0x00;
    m_pSocket = NULL;
}

void CAlarm::SetSocket(CSocket *pSock)
{
    m_pSocket = pSock;
}

int CAlarm::SendAlarm(ATM_AlarmInfo &alarmInfo, Rects &rects, IplImage *alarmImage)
{
    auto len = -1;
    if (alarmImage == NULL)
    {
        return len;
    }

    if (m_pSocket == NULL)
    {
        return len;
    }

    //printf("channel status[%d] = %d\n", alarmInfo.cardno, m_nChannelStatus[alarmInfo.cardno]);
    if (m_pSocket->GetValidLineCount()>0 && m_nChannelStatus[alarmInfo.cardno]==0)
    {
        bool bSame = CampareAlarm(rects);
        if (bSame)
        {
            cout<<"the same alarm !!!"<<endl;
            return 0;
        }
        else
        {
            cout<<"different alarm !!!"<<endl;
            m_LastAlarmRects.clear();
            m_LastAlarmRects = rects;
        }

        alarmInfo.warnID = m_nWarnID++;
        if (m_nWarnID > 65535)
        {
            m_nWarnID = 0;
        }

        IplImage* pBackupAlarmImage = cvCloneImage(alarmImage);
        
        CJSByteArray byteArr(128 * 1024);
        int nPackLen = PackAlarm(byteArr, alarmInfo, rects, *pBackupAlarmImage);
    
        if (nPackLen > 0)
        {
            len = m_pSocket->SendData(m_pSocket->GetLineByIndex(0), byteArr.GetData(), byteArr.Length());
            if (len > 0)
            {
                m_nChannelStatus[alarmInfo.cardno] = 1;
            }
        }


        AlarmNet backAlarm;
        backAlarm.alarmInfo = alarmInfo;
        backAlarm.rects = rects;    
        backAlarm.pIplImage = pBackupAlarmImage;

        m_locker.lock();
        m_backupAlarms.push_back(backAlarm);               //有后端连接和通道为空时，进行备份
        m_locker.unlock();
    }

    return len;
}

void CAlarm::AlarmAckHandle(char *buf)
{
    //取通道状态信息
    ChannelStatus channelStatus;

    channelStatus.nPackageID = ::ntohl(*(int*) (buf + 4));
    channelStatus.nChannelNO = *(BYTE*) (buf + 8);
    BYTE updateBkg = *(BYTE*) (buf + 9);

    printf("channelstatus, nPackageID=%d\n", channelStatus.nPackageID);
    printf("channelstatus, nChannelNO=%d\n", channelStatus.nChannelNO);
    printf("in handle ack package, backupAlarm count: %d", m_backupAlarms.size());

    m_locker.lock();

    BackupAlarms::iterator it = find_if(m_backupAlarms.begin(), m_backupAlarms.end(), 
                                    [&channelStatus](AlarmNet item) { return item.alarmInfo.cardno == channelStatus.nChannelNO 
                                                                    && item.alarmInfo.warnID == channelStatus.nPackageID;}
                                );

    if (it != m_backupAlarms.end())
    {
        int channel = channelStatus.nChannelNO;
        printf("channel %d handle success!!!!!!!!\n",
            channelStatus.nChannelNO);
        m_nChannelStatus[channel] = 0;
        m_AckInfo = updateBkg; //改新背景标志

        it->ackknowleged = true;
        
    }

    m_locker.unlock();
}


void CAlarm::ClearAllBackupAlarm()
{
    m_locker.lock();

    for_each(m_backupAlarms.begin(), m_backupAlarms.end(), [](AlarmNet item){cvReleaseImage(&item.pIplImage);});
    m_backupAlarms.clear();

    m_locker.unlock();
}

void CAlarm::ClearAllChannelStatus()
{
    for (int i=0; i<CHANNELNUM; i++)
    {
        m_nChannelStatus[i] = 0;
        //printf("has break, clear channel\n");
    }
}


BYTE CAlarm::GetAlarmAckInfo()
{
    return m_AckInfo;
}

void CAlarm::ResetAlarmAckInfo()
{
    m_AckInfo = 0x00;
}

void CAlarm::NoAlarm()
{
    m_LastAlarmRects.clear();
}


bool SameRect(const CvRect& x, const CvRect& y)
{
    int centerxx = x.x + x.width/2;
    int centerxy = x.y + x.height/2;

    int centeryx = y.x + y.width/2;
    int centeryy = y.y + y.height/2;

    long dx = abs(centerxx-centeryx);
    long dy = abs(centerxy-centeryy);

    int distance = sqrt((float)(dx*dx + dy*dy));

    return distance < 25;
}

bool Contains(const Rects& rects, const CvRect& rect)
{
    Rects::const_iterator it = find_if(rects.begin(), rects.end(), [=](CvRect r){return SameRect(r, rect);});
    return it != rects.end();
}


bool CAlarm::CampareAlarm(Rects &rects)
{
    for (Rects::const_iterator it = rects.begin();
         it != rects.end();
         ++it)
    {
        if (!Contains(m_LastAlarmRects, *it))
        {
            return false;
        }
    }
    
    return true;
    
}

void CAlarm::Print(Rects &rects)
{
    cout<<"rect size = "<<rects.size()<<endl;

    for_each(rects.begin(), rects.end(), 
        [](CvRect rc){cout<<"x="<<rc.x<<", "<<"y="<<rc.y<<", "<<"w="<<rc.width<<", "<<"h="<<rc.height<<endl;});
}


